這個章節來講對稱式加密一些毛細節 ,如果有心細的讀者已經發現在使用 DES 及 AES ,會看到 ECB 、CBC 、PKCS7、IV 等有如外星人的語言般參數或誰誰誰說什麼比較好,這章我們就是要來掀開這些毛神祕面紗
分組加密演算法是按分組大小來進行加解密操作的,如DES演算法的分組是64位,而AES是128位,但實際明文的長度一般要遠大於分組大小,這樣的情況如何處理呢?
這正是即工作模式要解決的問題:明文資料流怎樣按分組大小切分,資料不對齊的情況怎麼處理等等。
早在1981年,DES演算法公佈之後,NIST在標準文獻FIPS 81中公佈了4種工作模式:
2001年又針對AES加入了新的工作模式:
後來又陸續引入其它新的工作模式。在此僅介紹幾種常用的
ECB模式只是將明文按分組大小切分,然後用同樣的金鑰正常加密切分好的明文分組。
ECB的理想應用場景是短資料(如加密金鑰)的加密。此模式的問題是無法隱藏原明文資料的模式,因為同樣的明文分組加密得到的密文也是一樣的。
此模式是1976年由IBM所發明,引入了IV(初始化向量:Initialization Vector)的概念。IV是長度為分組大小的一組隨機,通常情況下不用保密,不過在大多數情況下,針對同一金鑰不應多次使用同一組IV。 CBC要求第一個分組的明文在加密運算前先與IV進行異或;從第二組開始,所有的明文先與前一分組加密後的密文進行異或。[區塊鏈(blockchain)的鼻祖!]
CBC模式相比ECB實現了更好的模式隱藏,但因為其將密文引入運算,加解密操作無法並行操作。同時引入的IV向量,還需要加、解密雙方共同知曉方可。
與CBC模式類似,但不同的地方在於,CFB模式先生成密碼流字典,然後用密碼字典與明文進行異或操作並最終生成密文。後一分組的密碼字典的生成需要前一分組的密文參與運算。
CFB模式是用分組演算法實現流演算法,明文資料不需要按分組大小對齊。
OFB模式與CFB模式不同的地方是:生成字典的時候會採用明文參與運算,CFB採用的是密文。
CTR模式同樣會產生流密碼字典,但同是會引入一個計數,以保證任意長時間均不會產生重複輸出。
CTR模式只需要實現加密演算法以生成字典,明文資料與之異或後得到密文,反之便是解密過程。CTR模式可以採用並行演算法處理以提升吞量,另外加密資料塊的訪問可以是隨機的,與前後上下文無關。
CCM模式,全稱是Counter with Cipher Block Chaining-Message Authentication Code,是CTR工作模式和CMAC認證演算法的組合體,可以同時資料加密和鑑別服務。
明文資料通過CTR模式加密成密文,然後在密文後面再附加上認證資料,所以最終的密文會比明文要長。具體的加密流程如下描述:先對明文資料認證併產生一個tag,在後續加密過程中使用此tag和IV生成校驗值U。然後用CTR模式來加密原輸入明文資料,在密文的後面附上校驗碼U。
GCM模式是CTR和GHASH的組合,GHASH操作定義為密文結果與金鑰以及訊息長度在GF(2^128)域上相乘。GCM比CCM的優勢是在於更高並行度及更好的效能。
GCM中的G就是指GMAC,C就是指CTR。
GCM可以提供對消息的加密和完整性校驗,另外,它還可以提供附加消息的完整性校驗。在實際應用場景中,有些信息是我們不需要保密,但信息的接收者需要確認它的真實性的,例如源IP,源端口,目的IP,IV,等等。因此,我們可以將這一部分作為附加消息加入到MAC值的計算當中。下圖的Ek表示用對稱秘鑰k對輸入做AES運算。最後,密文接收者會收到密文、IV(計數器CTR的初始值)、MAC值。
由於GCM現在屬於最嚴謹的加密模式,TLS 1.2標準使用的就是AES-GCM演算法。
Electronic CodeBook (ECB),不變的 key,需要加密器和解密器,加解密的複雜度可能不同。
Cipher Block Chaining (CBC),不變的 key,以及前一個密文會先針對明文加密。
Cipher FeedBack (CFB),類似 CBC,但前一個密文的結果只影響一部分的加密關係,然後將前一段密文狀態加密 key,再對明文加密。
Output FeedBack (OFB),類似於 CFB,將前一段的加密 key 拿回來加密,不依賴接收的密文狀態。
Counter (CTR),類似於 OFB,直接利用計數器作為加密 key。
有個概念我們要先知道。我們需要兩個元素去實行加密和解密:「初始向量」和「金鑰」。 你有可能會問初始向量有甚麼用途? 一般加密演算法,會將原始資料切成多個區塊進行加密動作, 如果我們只用一個金鑰值與每個明文區塊去做加密,這樣子所得到的每個密文區塊,都是相同的加密模式,會比較容易被破解。(如下圖)
所以加密演算法使用一種類似遞回的方法將資料加密,它是由三個輸入去產生一個加密過的片段,分別是「上一個已加密片段」、「現在還沒加密的資料片段」、「金鑰」。 因為演算法在一開始時並沒有「上一個加密過的片段」,這就是為什麼要用到初始向量的原因了。(如下圖)
用加密圖片來舉例來說明,即便不知道原理,也可以很直觀的感受,下圖為明文圖片:
經ECB模式加密的圖片:
圖中也正好驗證了AES的擴散效果:作為區域性圖案的羊頭,其紅顏色在加密後擴散到了整張圖片上。
經CBC模式有 IV 的加密的圖片:
IV 與金鑰(Key)不同, 其主要目的為讓加密模式的隨機化及混淆,因此並==無安全性==考量,因此無須保密
或額外加密
但由於重覆使用,容易導致泄露明文 block 的某些資訊,因此一直重用反而會導致加密模式失去安全性
不應在使用同一金鑰的情況下兩次使用同一個IV
注意一點==要使用 BMP 的影像格式==
使用 BMP 原因是 BMP檔案資訊不會壓縮,因為檔案很大通常不會在網路上使用這種格式
但對我們需求,不會因為加密檔案後造成無法解析圖片的問題
#產生 ECB 加密圖片
openssl enc -aes-128-ecb -e -in img.bmp -out img-ecb.bmp -K 111111
#產生 CBC 加密圖片
openssl enc -aes-128-cbc -e -in img.bmp -out img-cbc.bmp -K 111111 -iv 000000
為了程式碼簡潔,key 及 iv 只有填寫六位,長度不足,不過系統會自動補齊但會出現警告訊息
hex string is too short, padding with zero bytes to length
產生檔案後發現無法打開,這是因為二進位檔案都是透過 檔案抬頭(Header) 識別是什麼檔案,因為加密後,已經都被打散成亂數
上圖左圖是正常BMP 格式,右圖是加密後檔案,顯然抬頭已不見
接著使用 HEX 編輯器,將原始檔案開頭開始的 54 bytes 抬頭資訊複製到加密後檔案,讓其圖片可以正常被解析
我使用 HEX 編輯器是 Hex Fiend
下方是我原始檔案截取出的 54 bytes 讓大家看的比較清楚,使用時需要使用自己原始的BMP Header hex 資訊
424D6057 0B000000 00003600 00002800 0000DD01 00000702 00000100 18000000 00002A57 0B00120B 0000120B 00000000 00000000 0000
這樣就可以正常打開加密後的圖片
另外補充,用覆蓋開頭 54 bytes 或直接插入 54 bytes 都可以正常打開圖片
上面的加密模式,裡面包含了區塊加密法 和 串流加密法 使用的加密模式,只要確定你所需的場景,在選擇就不會出錯
但若無並行,資料缺失等考量,目前多數單純密文及範例都是使用 CBC ,雖然說越新的當然越好,但還是需要看需求考量
整理如下
特點 | 加密模式 |
---|---|
區塊加密: | ECB、CBC、CTR |
串流加密: | CFB、OFB |
傳遞誤差(資料不能有缺失): | CBC、CFB |
不傳遞誤差(資料允許缺失): | ECB、OFB、CTR |
可並行: | ECB、CTR |
不可並行: | CBC、OFB、CFB |
https://en.wikipedia.org/wiki/Galois/Counter_Mode
https://zh.wikipedia.org/wiki/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81
https://zh.wikipedia.org/wiki/%E6%B5%81%E5%AF%86%E7%A0%81
https://blog.csdn.net/T0mato_/article/details/53160772